import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { UserClient } from './assets/userClient.entity';
import { Repository } from 'typeorm';
import { util_Db_AddAnyWhere, util_Db_Add, util_Db_PageList, util_Db_Update } from '@/common/util/db';
import {
  UserClient_Update_Dto,
  UserClient_Create_Dto,
  UserClient_Find_Dto,
  UserClient_Disabled_Dto,
  UserClient_DistrubuteFind_Dto,
  UserClient_LinkDistrubute_Dto,
} from './assets/userClient.dto';
import {
  UserClient_AdmReturnUser_ReClass,
  UserClient_WebReturnUser_ReClass,
} from './assets/userClient.class';
import { JwtService } from '@nestjs/jwt';
import { IJwtStrategyPayload, IRequest } from '@/common/typeScripts/index';
import { AuthClientWeb_SignIn_ReClass } from '../authClientWeb/assets/authClientWeb.class';
import { Order } from '../order/assets/order.entity';
import {
  Constant_Enum_Enum_Order_PayStatus,
  Constant_Enum_Enum_Rebates_RebatesType,
  Constant_Enum_Enum_UserClient_Status,
  Constant_Enum_Enum_UserClient_Type,
} from '@/common/constants/enum';
import * as base62 from 'base62/lib/ascii';
import { Class_HttpException_Base } from '@/common/classes/httpException';
import { Rebates } from '../rebates/assets/rebates.entity';
import { InviteRelation } from '../inviteRelation/assets/inviteRelation.entity';

type IUserClient_Adm_FindByPage_Arguements = {
  list: UserClient_AdmReturnUser_ReClass[];
  totalElements: number;
};

@Injectable()
export class UserClient_Service {
  constructor(
    private jwtService: JwtService,
    @InjectRepository(Order)
    private order_Repository: Repository<Order>,
    @InjectRepository(UserClient)
    private userClient_Repository: Repository<UserClient>,
  ) {}

  userClient_WebUtil_ReturnUser(user_Client: UserClient): UserClient_WebReturnUser_ReClass {
    return {
      id: user_Client.id,
      userName: user_Client.userName,
      phone: user_Client.phone,
      email: user_Client.email,
      headimgurl: user_Client.headimgurl,
      distributionCode: user_Client.distributionCode,
    };
  }

  async userClient_WebUtil_ReturnInfoData(
    user_Client: UserClient,
    payload: IJwtStrategyPayload,
  ): Promise<AuthClientWeb_SignIn_ReClass> {
    return {
      userClient: this.userClient_WebUtil_ReturnUser(user_Client) as UserClient_WebReturnUser_ReClass,
      token: await this.jwtService.signAsync(payload),
    };
  }

  async userClient_WebUtil_Create(
    body: UserClient_Create_Dto,
  ): Promise<UserClient_AdmReturnUser_ReClass> {
    const result = await util_Db_Add<UserClient>({
      createDto: body,
      repository: this.userClient_Repository,
      returnObj: true,
    });
    result.distributionCode = base62.encode(new Date().getTime() + result.id * 100);
    await this.userClient_Repository.save(result);
    return this.userClient_AdmUtil_ReturnUser(result);
  }

  async userClient_Adm_FindByPage(
    query: UserClient_Find_Dto,
  ): Promise<IUserClient_Adm_FindByPage_Arguements> {
    const { size, page } = query;
    return (await util_Db_PageList<UserClient>({
      queryBuilder: this.userClient_Repository
        .createQueryBuilder('userClient')
        .select([
          'userClient.id AS id',
          'userClient.userName AS userName',
          'userClient.phone AS phone',
          'userClient.email AS email',
          'userClient.statusUser AS statusUser',
          'userClient.headimgurl AS headimgurl',
        ]),
      query: {
        'userClient.userName': query.userName,
        'userClient.phone': query.phone,
        'userClient.email': query.email,
        'userClient.id': query.id,
        'userClient.statusUser': query.statusUser,
        size,
        page,
      },
      isRaw: true,
    })) as IUserClient_Adm_FindByPage_Arguements;
  }
  async userClient_FindOneByCode(query: { distributionCode: string }) {
    return await this.userClient_Repository
      .createQueryBuilder('userClient')
      .where('userClient.distributionCode = :distributionCode', {
        distributionCode: query.distributionCode,
      })
      .getOne();
  }

  async userClient_FindOneById(query: { id: number }) {
    return await this.userClient_Repository
      .createQueryBuilder('userClient')
      .where('userClient.id = :id', {
        id: query.id,
      })
      .getOne();
  }

  async userClient_FindOneByPhoneOrEmail(query: { phone: number; email: string }) {
    const queryBuilder = this.userClient_Repository.createQueryBuilder('userClient');
    return await util_Db_AddAnyWhere({ queryBuilder, obj: query as Record<string, unknown> }).getOne();
  }

  async userClient_FindOneByOpenId(obj: { openid: string }) {
    return await this.userClient_Repository
      .createQueryBuilder('userClient')
      .where('userClient.openid = :openid', {
        openid: obj.openid,
      })
      .getOne();
  }

  async userClient_Adm_Disabled(body: UserClient_Disabled_Dto) {
    const useClient = await this.userClient_FindOneById({ id: body.id });
    if (!useClient) new Class_HttpException_Base('没有该用户');
    useClient.statusUser =
      useClient.statusUser == Constant_Enum_Enum_UserClient_Status.UserClient_Status_Disable
        ? Constant_Enum_Enum_UserClient_Status.UserClient_Status_Enable
        : Constant_Enum_Enum_UserClient_Status.UserClient_Status_Disable;
    await this.userClient_Repository.save(useClient);
    return useClient.statusUser == Constant_Enum_Enum_UserClient_Status.UserClient_Status_Disable
      ? '拉黑成功'
      : '取消拉黑成功';
  }

  async userClient_Web_Update(body: UserClient_Update_Dto): Promise<UserClient_WebReturnUser_ReClass> {
    const user_Client = await util_Db_Update({
      findOne: () => this.userClient_FindOneById({ id: body.id }),
      updateDto: body,
      repository: this.userClient_Repository,
      isReturnData: true,
    });
    return this.userClient_WebUtil_ReturnUser(user_Client);
  }

  userClient_AdmUtil_ReturnUser(body: UserClient): UserClient_AdmReturnUser_ReClass {
    return {
      id: body.id,
      userName: body.userName,
      phone: body.phone,
      email: body.email,
      statusUser: body.statusUser,
      headimgurl: body.headimgurl,
      distributionCode: body.distributionCode,
    };
  }

  async userClient_WebUtil_isNewUser(req: IRequest) {
    const result = await this.order_Repository
      .createQueryBuilder('order')
      .where('order.userClientId = :userClientId', {
        userClientId: req.user.userId,
      })
      .andWhere('order.status = :status', {
        status: Constant_Enum_Enum_Order_PayStatus.order_PayStatus_Pay,
      })
      .getMany();
    return result.length == 0 ? true : false;
  }

  async userClient_DistributeFindByPage(query: UserClient_DistrubuteFind_Dto) {
    return await util_Db_PageList<UserClient>({
      queryBuilder: this.userClient_Repository
        .createQueryBuilder('userClient')
        .leftJoin('userClient.rebatesInviter', 'rebatesInviter')
        .leftJoin('rebatesInviter.inviter', 'inviter')
        .select([
          'userClient.id AS id',
          'userClient.userName AS userName',
          'userClient.distributionType AS distributionType',
          'inviter.userName AS inviterUserName',
          'inviter.id AS inviterId',
        ])
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('COUNT(rebates.id)')
            .from(Rebates, 'rebates')
            .where('rebates.inviter = userClient.id')
            .andWhere('rebates.rebatesType = :rebatesTypeq', {
              rebatesTypeq: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_FirstOrder,
            });
          if (query.startTime) {
            subQb.andWhere('rebates.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'firstCount')
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('COUNT(rebates.id)')
            .from(Rebates, 'rebates')
            .where('rebates.inviter = userClient.id')
            .andWhere('rebates.rebatesType = :rebatesType', {
              rebatesType: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_SecondedOrder,
            });
          if (query.startTime) {
            subQb.andWhere('rebates.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'secondCount')
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('SUM(rebates.rebatesMoney)')
            .from(Rebates, 'rebates')
            .where('rebates.inviter = userClient.id')
            .andWhere('rebates.rebatesType = :rebatesTypew', {
              rebatesTypew: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_FirstOrder,
            });
          if (query.startTime) {
            subQb.andWhere('rebates.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'firstMoney')
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('SUM(rebates.rebatesMoney)')
            .from(Rebates, 'rebates')
            .where('rebates.inviter = userClient.id')
            .andWhere('rebates.rebatesType = :rebatesTypee', {
              rebatesTypee: Constant_Enum_Enum_Rebates_RebatesType.Rebates_RebatesType_SecondedOrder,
            });
          if (query.startTime) {
            subQb.andWhere('rebates.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('rebates.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'scondedMoney')
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('COUNT(inviteRelation.id)')
            .from(InviteRelation, 'inviteRelation')
            .where('inviteRelation.inviter = userClient.id');
          if (query.startTime) {
            subQb.andWhere('inviteRelation.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('inviteRelation.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'inviteNum')
        .addSelect((subQuery) => {
          const subQb = subQuery
            .select('COUNT(inviteRelation.id)')
            .from(InviteRelation, 'inviteRelation')
            .where('inviteRelation.inviter = userClient.id')
            .leftJoin(Rebates, 'rebate', 'rebate.inviteeId = inviteRelation.inviteeId')
            .andWhere('rebate.id IS NOT NULL');
          if (query.startTime) {
            subQb.andWhere('inviteRelation.createTime >= :startTime', {
              startTime: query.startTime,
            });
          }
          if (query.endTime) {
            subQb.andWhere('inviteRelation.createTime <= :endTime', { endTime: query.endTime });
          }
          return subQb;
        }, 'inviteHasOrderNum'),
      query: {
        'userClient.userName': query.inviterName,
        'userClient.distributionType': query.distributionType,
        'userClient.id': query.inviterId,
        size: query.size,
        page: query.page,
      },
      isRaw: true,
    });
  }

  async userClient_ChangeType(id: string) {
    const result = await this.userClient_FindOneById({ id: Number(id) });
    if (!result) throw new Class_HttpException_Base('不存在该记录');
    result.distributionType =
      result.distributionType !== Constant_Enum_Enum_UserClient_Type.UserClient_Type_Lock
        ? Constant_Enum_Enum_UserClient_Type.UserClient_Type_Lock
        : Constant_Enum_Enum_UserClient_Type.UserClient_Type_Normal;
    await this.userClient_Repository.save(result);
    return '修改成功';
  }

  async userClientWeb_linkDistrubute(req: IRequest, body: UserClient_LinkDistrubute_Dto) {
    const result = await this.userClient_FindOneById({ id: Number(req.user.userId) });
    if (!result) throw new Class_HttpException_Base('不存在该记录');
    const order = await this.order_Repository
      .createQueryBuilder('order')
      .leftJoin('order.userClient', 'userClient')
      .where('userClient.id = :userClientId', { userClientId: req.user.userId })
      .getOne();
    if (order) throw new Class_HttpException_Base('已产生订单,不可进行绑定!');
    result.distributionCode = body.distributionCode;
    await this.userClient_Repository.save(result);
    return '绑定成功';
  }
}
